package nl.utwente.eemcs.graph;

import java.util.HashMap;

/**
 * Edge represents a connection between two nodes.
 * Edges can be of three types and can be labeled.
 * @author Evert Duipmans
 */
public class Edge {
	/**
	 * Start node
	 */
	private Node start;
	
	/**
	 * End node
	 */
	private Node end;
	
	/**
	 * Edge type
	 */
	private EdgeType edgeType;
	
	/**
	 * Label of the edge
	 */
	private String label = "";
	
	/**
	 * List with attributes of the edge, used for storing relevant information
	 */
	protected HashMap<String, Object> attributes;	
	
	/**
	 * Creates an edge
	 * @param start Start node
	 * @param end End node
	 * @param edgeType Edge type
	 */
	public Edge(Node start, Node end, EdgeType edgeType) {
		this.start = start;
		this.end = end;
		this.edgeType = edgeType;
		this.attributes = new HashMap<String, Object>();
	}
	
	/**
	 * Creates an edge
	 * @param start Start node
	 * @param end End node
	 * @param edgeType Edge type
	 * @param label Label
	 */
	public Edge(Node start, Node end, EdgeType edgeType, String label) {
		this(start, end, edgeType);
		this.label = label;
	}	

	/**
	 * Get the label
	 * @return Label
	 */
	public String getLabel() {
		return label;
	}

	/**
	 * Set label of the edge
	 * @param label Label
	 */
	public void setLabel(String label) {
		this.label = label;
	}

	/**
	 * Get start node of the edge
	 * @return start node of the edge
	 */
	public Node getStart() {
		return start;
	}

	/**
	 * Set start node
	 * @param start start node
	 */
	public void setStart(Node start) {
		this.start = start;
	}

	/**
	 * Get the end node of the edge
	 * @return End node
	 */
	public Node getEnd() {
		return end;
	}

	/**
	 * Set end node
	 * @param end End node
	 */
	public void setEnd(Node end) {
		this.end = end;
	}

	/**
	 * Get edge type
	 * @return Edge type
	 */
	public EdgeType getEdgeType() {
		return edgeType;
	}

	/**
	 * Set edge type
	 * @param edgeType Edge type
	 */
	public void setEdgeType(EdgeType edgeType) {
		this.edgeType = edgeType;
	}
	
	/**
	 * Add attribute to the attributes list
	 * @param key Name of the attribute
	 * @param value Value of the attribute
	 */
	public void addAttribute(String key, Object value) {
		this.attributes.put(key, value);
	}
	
	/**
	 * Check if the current item has an attribute with a certain name
	 * @param key Name of the element
	 * @return True, if the attribute exists in the attribute list
	 */
	public boolean hasAttribute(String key) {
		return this.attributes.containsKey(key);
	}
	
	/**
	 * Get a value from the attribute list
	 * @param key Name of the attribute
	 * @return Value of the attribute
	 */
	public Object getAttribute(String key) {
		return this.attributes.get(key);
	}
	
	/**
	 * Get the whole attributes list
	 * @return Hash map with attributes
	 */
	public HashMap<String, Object> getAttributes() {
		return this.attributes;
	}	
	
	/**
	 * Simple representation of edge as string
	 */
	@Override
	public String toString() {
		String result = this.start.toString();
		
		switch (this.edgeType) {
		case Communication:
			result += "::>";
			break;
		case Data:
			result += "~~>";
			break;
		default:
			result += "-->";
			break;
		}
		result += this.end.toString();
		return result;
	}
	
	public String toComplexString() {
		String result = this.toString();
		if (edgeType == EdgeType.Data) {
			result += "[";
			for (String key : attributes.keySet())
				result += key + ": " + attributes.get(key).toString() + ", ";
			result += "]";
		}
		return result;
	}
}
